home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
Compilers⁄Interps
/
kevoSource
/
portEvents.c
< prev
next >
Wrap
Text File
|
1993-05-16
|
44KB
|
1,649 lines
/* Kevo -- a prototype-based object-oriented language */
/* (c) Antero Taivalsaari 1991-1993 */
/* Some parts (c) Antero Taivalsaari 1986-1988 */
/* portEvents.c: The graphical user interface event manager */
#include "global.h"
#include "portGlobal.h"
/*---------------------------------------------------------------------------*/
/* Graphical user interface (GUI) initialization */
/* initGUI(): initialize the graphical user interface */
void initGUI()
{
WindowPtr newWindow;
GrafPtr savePort;
TEHandle newText;
WINFO* newWinfo;
Rect viewRect, destRect;
WStateData** wDataHdl;
InitGraf(&thePort);
InitFonts();
FlushEvents(everyEvent, 0);
InitWindows();
InitMenus();
TEInit();
InitDialogs(0L);
InitCursor();
MaxApplZone();
/* Set the default window growing and dragging limits */
SetRect(&limitRect, 16, 24, screenBits.bounds.right-8, screenBits.bounds.bottom-8);
/* Initialize the standard window size rectangle */
SetRect(&standardRect, 60, 80, STANDARDWINDOWWIDTH+60, STANDARDWINDOWHEIGHT+80);
/* Create and display the first task window */
if (!(newWindow = NewWindow(0L, &standardRect, "\pKevo Task", TRUE,
documentProc+8, (WindowPtr)-1, TRUE, 0L))) {
fprintf(confile, "Could not allocate new window.\n");
fprintf(confile, "Cannot continue. Exiting.\n");
exit(1);
}
/* Set the standard size of the window for zooming */
wDataHdl = (WStateData**)((WindowPeek)newWindow)->dataHandle;
BlockMove(&standardRect, &(*wDataHdl)->stdState, sizeof(Rect));
/* Prepare to build a new TE (TextEdit) for the newly created window */
GetPort(&savePort);
SetPort(newWindow);
/* Initial text settings */
TextFont(monaco);
TextFace(0);
TextSize(9);
/* Set the view and destination rectangles for the TE */
BlockMove(&newWindow->portRect, &viewRect, sizeof(Rect));
viewRect.right -= SCROLLBARWIDTH;
viewRect.bottom -= SCROLLBARWIDTH;
BlockMove(&newWindow->portRect, &destRect, sizeof(Rect));
destRect.right -= (SCROLLBARWIDTH + 4);
destRect.bottom -= (SCROLLBARWIDTH + 4);
destRect.left += 4;
/* Allocate the TextEdit */
newText = TENew(&destRect, &viewRect);
if (!newText) {
fprintf(confile, "Could not allocate new TextEdit.\n");
fprintf(confile, "Cannot continue. Exiting.\n");
exit(1);
}
SetPort(savePort);
/* Set automatic scrolling */
TEAutoView(TRUE, newText);
/* Create a window information structure for the TextEdit window */
newWinfo = createWinfo(TEWKind, newText);
/* Then set the RefCon field of the new window to point to the winfo struct */
SetWRefCon(newWindow, (long)newWinfo);
/* Assign the new window to the current task */
(*up)->window = (int*)newWindow;
/* Initialize the UI pointers to the currently user-chosen task and TE */
theText = newText;
theTask = up;
/* Receive text from clipboard, and activate the TE */
TEFromScrap();
TEActivate(theText);
/* Initialize the information for CUTting, COPYing, and PASTEing objects */
ClipObject = NIL;
ClipList = createList();
ClipContext = copyContext(dummyContext);
ClipMode = CLIP_COPY;
/* Initialize menus and set the correct display mode */
initMenus();
doChangeGUIMode(TEWKind);
SelectWindow(newWindow);
aboutKevo();
/* Initialize the deadlock detection variable */
lastEventTime = TickCount();
#ifdef UNIX
/* Initialize the Curses library */
/* Ensure that input characters will be not echoed */
/* Set character at a time input mode */
initscr();
noecho();
cbreak();
#endif
}
/* Initialize menus by reading them from the resource file */
void initMenus()
{
appleMenu = GetMenu(APPLE_MENU);
AddResMenu(appleMenu, 'DRVR');
fileMenu = GetMenu(FILE_MENU);
edit1Menu = GetMenu(EDIT1_MENU);
tasksMenu = GetMenu(TASKS_MENU);
multitaskMenu = GetMenu(MULTITASK_MENU);
debugMenu = GetMenu(DEBUG_MENU);
edit2Menu = GetMenu(EDIT2_MENU);
viewMenu = GetMenu(VIEW_MENU);
toolsMenu = GetMenu(TOOLS_MENU);
/* propagationMenu = GetMenu(PROPAGATION_MENU); */
windowMenu = NewMenu(WINDOW_MENU, "\pWindows");
}
/* Display the 'about' box */
void aboutKevo()
{
EventRecord mouseEvent;
DialogPtr theDialog;
GrafPtr savePort;
GetPort(&savePort); /* save current GrafPort */
/* get dialog ptr from resource file */
if (theDialog = GetNewDialog (ABOUT_DIALOG, 0, (WindowPtr)-1)) {
/* Now make it visible */
ShowHide (theDialog, TRUE);
DrawDialog(theDialog);
while(!WaitNextEvent(mDownMask + keyDownMask, &mouseEvent, eventSlice, 0L));
DisposDialog(theDialog);
}
else {
SysBeep (1);
fprintf(confile, "== About window is not available (check resource fork) ==\n");
}
SetPort(savePort); /* restore saved GrafPort */
}
/*---------------------------------------------------------------------------*/
/* Event loop */
/*
The following routine defines the Macintosh-specific event loop.
This routine takes care of responding to mouse, keyboard, etc. events
coming from the user.
Note that in Kevo the event loop is not actually a loop, but it is
a piece of code which is called frequently from the task switching
operation 'yield()' (see kernel.c). This strategy has been chosen
because in Kevo the heart of the system is the inner interpreter --
not the event loop.
*/
void EventLoop()
{
/*
Do not poll events when executing critical regions.
This is important, because otherwise the user might activate
task switching and change multitasking settings from the user interface
even when critical regions are being executed.
However, if the event loop will has not been invoked for 20 seconds
(1200 Mac clock ticks), the protected region will be unlocked by force
in order to avoid unterminating loops.
*/
if (inProtRegion) {
if (TickCount() - lastEventTime < 1200) return;
fprintf(confile, "== Critical region unlocked by the system (deadlock suspected) ==\n");
inProtRegion = 0;
multitasking = mtStore;
SysBeep(1); SysBeep(1);
}
/*
Set the supervisor mode on so as to prevent tasks from being affected
by possible errors resulting from commands given from the user interface.
*/
supervisor = TRUE;
lastEventTime = TickCount();
/* Blink the text cursor */
if (theText) TEIdle(theText);
if (WaitNextEvent (everyEvent, &theEvent, eventSlice, 0L)) {
switch (theEvent.what) {
case keyDown:
case autoKey:
doKeyEvent();
break;
case mouseDown:
doMouseEvent();
break;
case updateEvt:
doUpdateEvent();
break;
case activateEvt:
doActivateEvent();
break;
case app4Evt:
doSuspendResume();
break;
}
}
/* Calculate the next time when event loop should be invoked */
nextTime = TickCount() + eventDelay;
supervisor = FALSE;
/* Set the correct multitasking mode (see 'doMenuItem()') */
doFlags();
}
/* Some keyboard key was pressed */
void doKeyEvent()
{
char c = theEvent.message & charCodeMask;
if (theEvent.modifiers & cmdKey) { /* Menu command key */
/* Ensure that extra menu key shortcuts will be disabled */
doMenuDisable();
doMenuItem(MenuKey(c));
}
else {
switch (GUIMode) {
case GUIShell:
/* Does current window have a TE? */
/* If so, put the char to the active TE */
if (theText) TEKey(c, theText);
/* If the window has an associated task, put char to its text buffer. */
if (theTask) {
/* Return chars are put twice to the buffer */
/* This is because our parser needs two separators between lines */
if (c == CR) putToKeyBuffer(theTask, CR);
if (c >= BL || c == CR) putToKeyBuffer(theTask, c);
else if (c == BS) removeFromKeyBuffer(theTask);
}
break;
case GUIBrowser: {
/* Handle the renaming of properties */
WindowPtr browserWindow = FrontWindow();
ListHandle iconList = getBrowserIcons(browserWindow);
Cell cell = LLastClick(iconList);
if (cell.h >= 0 && cell.v >= 0 && LGetSelect(FALSE, &cell, iconList)) {
/* Some cell is currently selected */
if (c == BS) removeFromCell(iconList, cell);
else if (c == CR) renameCell(browserWindow, cell);
else if (c == BL) SysBeep(1);
else addToCell(iconList, cell, c);
}
else SysBeep(1);
break;
}
}
}
}
/* Mouse key was pressed */
void doMouseEvent()
{
WindowPtr mouseWindow;
short location;
location = FindWindow(theEvent.where, &mouseWindow);
switch (location)
{
case inDesk:
break;
case inMenuBar:
doMenuDisable();
doMenuMarkers();
doMenuItem(MenuSelect(theEvent.where));
break;
case inSysWindow:
SystemClick(&theEvent, mouseWindow);
break;
case inContent:
if (mouseWindow != FrontWindow() || !((WindowPeek)mouseWindow)->hilited) {
/* Select another Kevo window */
SelectWindow(mouseWindow);
}
else {
short controlCode;
ControlHandle theControl;
GlobalToLocal(&theEvent.where);
if (controlCode = FindControl(theEvent.where, mouseWindow, &theControl)) {
/* Mouse clicked in a control */
if (controlCode == inThumb) doThumb(mouseWindow, theControl, controlCode);
else TrackControl(theControl, theEvent.where, doWindowControls);
}
else {
/* Mouse clicked outside any control -> */
/* Pass the mouse click to the current window */
doWindowClick(mouseWindow);
}
}
break;
case inDrag:
SelectWindow(mouseWindow);
DragWindow(mouseWindow, theEvent.where, &limitRect);
break;
case inGrow: {
long growResult = GrowWindow(mouseWindow, theEvent.where, &limitRect);
if (growResult != 0) {
GrafPtr savePort;
GetPort(&savePort);
SetPort(mouseWindow);
SizeWindow(mouseWindow, LoWord(growResult), HiWord(growResult), TRUE);
doResizeWindow(mouseWindow, LoWord(growResult), HiWord(growResult));
DrawGrowIcon(mouseWindow);
SetPort(savePort);
}
break;
}
case inZoomIn:
case inZoomOut:
if (TrackBox(mouseWindow, theEvent.where, location))
doZoomWindow(mouseWindow, location);
break;
case inGoAway:
if (TrackGoAway(mouseWindow, theEvent.where)) doCloseWindow(mouseWindow);
break;
}
}
/* A window needs to be updated */
void doUpdateEvent()
{
WindowPtr thisWindow = (WindowPtr)theEvent.message;
int wKind = getWindowKind(thisWindow);
GrafPtr savePort;
/* Update a window, but only if it belongs to Kevo */
if (((WindowPeek)thisWindow)->windowKind == userKind) {
GetPort(&savePort);
SetPort(thisWindow);
BeginUpdate(thisWindow);
switch (wKind) {
case PlainWKind:
/* xxx Some vectored routine should be put here */
/* to allow updating of graphics windows etc. */
break;
case TEWKind: {
TEHandle thisTE;
if (thisTE = getWindowTE(thisWindow)) {
EraseRect(&(*thisTE)->viewRect);
TEUpdate(&(*thisTE)->viewRect, thisTE);
}
break;
}
case BrowserWKind:
case CloneBrWKind:
{
/* Redraw all the visible browser icons (cells) */
ListHandle iconList = getBrowserIcons(thisWindow);
if (iconList) {
EraseRect(&thisWindow->portRect);
LUpdate(thisWindow->visRgn, iconList);
}
break;
}
}
DrawGrowIcon(thisWindow);
EndUpdate(thisWindow);
SetPort(savePort);
}
}
/* A window is changed from active to passive, or vice versa */
void doActivateEvent()
{
WindowPtr thisWindow = (WindowPtr)theEvent.message;
int wKind = getWindowKind(thisWindow);
SetPort(thisWindow);
if (theEvent.modifiers & activeFlag) {
/* The window is activated */
theTask = determineTask(thisWindow);
switch (wKind) {
case PlainWKind:
theText = NIL;
break;
case TEWKind: {
TEHandle thisTE;
if (thisTE = getWindowTE(thisWindow)) {
TEActivate(thisTE);
theText = thisTE;
}
break;
}
case BrowserWKind:
case CloneBrWKind:
{
ListHandle iconList = getBrowserIcons(thisWindow);
if (iconList) LActivate(TRUE, iconList);
updateBrowser(thisWindow);
theText = NIL;
break;
}
}
/* If singletasking, change the currently executing task */
if (!multitasking) doSelectTask(thisWindow, theTask);
/* Set the appropriate GUI mode (change menus if needed) */
doChangeGUIMode(wKind);
InitCursor(); /* Ensure that we have the correct mouse cursor */
}
else {
TEHandle thisTE;
/* The window is passivated */
theTask = NIL;
switch (wKind) {
case PlainWKind:
case TEWKind:
if (thisTE = getWindowTE(thisWindow)) TEDeactivate(thisTE);
break;
case BrowserWKind:
case CloneBrWKind:
{
ListHandle iconList = getBrowserIcons(thisWindow);
if (iconList) LActivate(FALSE, iconList);
break;
}
}
}
DrawGrowIcon((WindowPtr)theEvent.message);
}
/* The Kevo system becomes suspended or resumed by the Mac OS */
/* Suspended = moved from foreground to background. */
/* Resumed = moved from background to foreground. */
void doSuspendResume()
{
int activate;
WindowPtr mouseWindow = FrontWindow();
/* Suspend == false, Resume == true */
activate = (theEvent.message & 1) ? TRUE : FALSE;
if (((WindowPeek)mouseWindow)->windowKind == userKind) {
/* Activate/deactivate */
if (activate) {
SelectWindow(mouseWindow);
HiliteWindow(mouseWindow, TRUE);
TEFromScrap();
InitCursor(); /* Ensure that we have the correct mouse cursor */
}
else {
HiliteWindow(mouseWindow, FALSE);
/* Copy the contents of TE scrap to the clipboard */
/* so that other applications can use our clipboard contents */
ZeroScrap();
TEToScrap();
}
}
}
/* Pass a mouse click to a window */
void doWindowClick(thisWindow)
WindowPtr thisWindow;
{
/* Note that by now 'theEvent.where' must have been converted to local coordinates */
switch (getWindowKind(thisWindow)) {
case PlainWKind:
case TEWKind:
/* Pass the mouse click to the current window */
if (theText) {
if (PtInRect(theEvent.where, &(*theText)->viewRect))
TEClick(theEvent.where, theEvent.modifiers & shiftKey, theText);
}
break;
case BrowserWKind:
case CloneBrWKind:
{
ListHandle iconList = getBrowserIcons(thisWindow);
if (iconList) {
int doubleClick;
int optKey = theEvent.modifiers & optionKey;
if (PtInRect(theEvent.where, &(*iconList)->rView))
doubleClick = LClick(theEvent.where, theEvent.modifiers, iconList);
if (doubleClick) handleDoubleClick(thisWindow, optKey);
}
break;
}
}
}
/* Operate the window controls (scroll bars, etc.) */
/*
This routine is called by Mac Toolbox routine 'TrackControl' so
it must be declared a Pascal routine.
*/
pascal void doWindowControls(theControl, controlCode)
ControlHandle theControl;
short controlCode;
{
WindowPtr thisWindow = FrontWindow();
switch(getWindowKind(thisWindow)) {
case PlainWKind:
case TEWKind:
/* In the current implementation, only browser windows have scroll bars */
break;
case BrowserWKind:
case CloneBrWKind:
{
ListHandle iconList = getBrowserIcons(thisWindow);
int vertical = (theControl == ((*iconList)->vScroll));
int horizontal = (theControl == ((*iconList)->hScroll));
switch (controlCode) {
case inUpButton:
if (vertical) LScroll(0, -1, iconList);
if (horizontal) LScroll(-1, 0, iconList);
break;
case inDownButton:
if (vertical) LScroll(0, 1, iconList);
if (horizontal) LScroll(1, 0, iconList);
break;
case inPageUp:
if (vertical) LScroll(0, -15, iconList);
if (horizontal) LScroll(-4, 0, iconList);
break;
case inPageDown:
if (vertical) LScroll(0, 15, iconList);
if (horizontal) LScroll(4, 0, iconList);
break;
}
}
}
}
/* Operate a scroll bar thumb */
/* In the current implementation, only browser windows can have scroll bars */
void doThumb(thisWindow, theControl, controlCode)
WindowPtr thisWindow;
ControlHandle theControl;
short controlCode;
{
ListHandle iconList = getBrowserIcons(thisWindow);
int vertical = (theControl == ((*iconList)->vScroll));
int horizontal = (theControl == ((*iconList)->hScroll));
int beginValue;
int endValue;
beginValue = GetCtlValue(theControl);
TrackControl(theControl, theEvent.where, NIL);
endValue = GetCtlValue(theControl);
if (vertical) LScroll(0, endValue-beginValue, iconList);
if (horizontal) LScroll(endValue-beginValue, 0, iconList);
}
/* Resize window contents (invoked when the size of a window is changed) */
void doResizeWindow(thisWindow, newSizeH, newSizeV)
WindowPtr thisWindow;
short newSizeH;
short newSizeV;
{
int wKind = getWindowKind(thisWindow);
EraseRect(&thisWindow->portRect);
InvalRect(&thisWindow->portRect);
switch (wKind) {
case PlainWKind:
case TEWKind:
/* see 'portWindow.c' */
resizeWindowTE(thisWindow);
break;
case BrowserWKind:
case CloneBrWKind:
{
ListHandle iconList = getBrowserIcons(thisWindow);
LSize(newSizeH-15, newSizeV-15, iconList);
break;
}
}
}
/* Zoom the window to the standard size */
void doZoomWindow(thisWindow, partCode)
WindowPtr thisWindow;
short partCode;
{
GrafPtr savePort;
int wKind = getWindowKind(thisWindow);
GetPort(&savePort);
SetPort(thisWindow);
/* Browser window size can be determined automatically */
if (wKind == BrowserWKind || wKind == CloneBrWKind)
determineBrowserWindowSize(thisWindow);
else {
int offsetLeft = 0 - thisWindow->portBits.bounds.left;
int offsetTop = 0 - thisWindow->portBits.bounds.top;
WStateData** wDataHdl;
Rect newRect;
/* Automatically calculate the correct browser size for zooming */
SetRect(&newRect, offsetLeft, offsetTop,
offsetLeft + STANDARDWINDOWWIDTH,
offsetTop + STANDARDWINDOWHEIGHT);
wDataHdl = (WStateData**)((WindowPeek)thisWindow)->dataHandle;
BlockMove(&newRect, &(*wDataHdl)->stdState, sizeof(Rect));
}
ZoomWindow(thisWindow, partCode, FALSE);
doResizeWindow(thisWindow, thisWindow->portRect.right, thisWindow->portRect.bottom);
SetPort(savePort);
}
/* Close a window */
void doCloseWindow(thisWindow)
WindowPtr thisWindow;
{
int wKind;
if (countVisibleWindows() <= 1) {
fprintf(confile, "== Cannot close the only visible window in the system ==\n");
return;
}
switch (wKind = getWindowKind(thisWindow)) {
case PlainWKind:
/* see 'portWindows.c' */
deleteWindow(thisWindow);
break;
case TEWKind:
if (getMethodContext(thisWindow)) {
/* see 'portBrowser.c' */
redefineMethod(thisWindow);
}
deleteWindow(thisWindow);
break;
case BrowserWKind:
case CloneBrWKind:
{
/* see 'portBrowser.c' */
deleteBrowser(thisWindow);
break;
}
}
}
/* Change execution mode on the basis of flags set by 'doMenuItem()' */
void doFlags()
{
if (cooperativeFlag) {
if (cooperativeFlag > 0) {
if (multitasking)
fprintf(confile, "== Cooperative multitasker active ==\n");
else fprintf(confile, "== Cooperative singletasker active ==\n");
cooperativeFlag = 0;
pCooperative();
}
else {
if (multitasking)
fprintf(confile, "== Preemptive multitasker active ==\n");
else fprintf(confile, "== Preemptive singletasker active ==\n");
cooperativeFlag = 0;
pPreemptive();
}
}
if (traceFlag) {
if (traceFlag == TRACE) {
traceFlag = 0;
traceInterpreter();
}
else if (traceFlag == FULLTRACE) {
traceFlag = 0;
fullTraceInterpreter();
}
else {
traceFlag = 0;
ownLongJmp();
}
}
}
/*
In singletasking mode, selecting a window causes the (possible) task
in the selected window to run. This operation takes care of yielding
the control to the correct task.
'thisTask' is passed as a parameter so that we don't necessarily have to
run 'determineTask'.
*/
void doSelectTask(thisWindow, thisTask)
int thisWindow;
TASK** thisTask;
{
/* We may not interrupt the execution of a protected region */
/* if (inProtRegion) return; */
switch (getWindowKind(thisWindow)) {
case PlainWKind:
case TEWKind:
if (thisTask && isActivated(thisTask)) yieldTo(thisTask);
break;
case BrowserWKind:
case CloneBrWKind:
{
if (browserTask && isActivated(browserTask)) yieldTo(browserTask);
break;
}
}
}
/* Set the appropriate GUI mode, changing the menus if needed */
/* The possible modes are:
GUIShell: the normal execution environment
GUIBrowser: object browser
*/
void doChangeGUIMode(newWKind)
int newWKind;
{
if (newWKind == PlainWKind || newWKind == TEWKind) {
/* Enable these menus so as to ensure that they will be displayed */
EnableItem(tasksMenu, 0);
EnableItem(debugMenu, SET_BREAK_MENUITEM);
EnableItem(debugMenu, REMOVE_BREAK_MENUITEM);
if (!theTask)
DisableItem(edit1Menu, BROWSE_MENUITEM);
else EnableItem(edit1Menu, BROWSE_MENUITEM);
if (GUIMode != GUIShell) {
/* Remove the previous menus */
ClearMenuBar();
InsertMenu(appleMenu, 0);
InsertMenu(fileMenu, 0);
InsertMenu(edit1Menu, 0);
InsertMenu(tasksMenu, 0);
InsertMenu(debugMenu, 0);
InsertMenu(multitaskMenu, 0);
InsertMenu(windowMenu, 0);
DisableItem(fileMenu, SAVE_IMAGE_MENUITEM);
DrawMenuBar();
GUIMode = GUIShell;
}
else DrawMenuBar();
return;
}
if (newWKind == BrowserWKind || newWKind == CloneBrWKind) {
/* Enable these menus so as to ensure that they will be displayed */
EnableItem(viewMenu, 0);
EnableItem(toolsMenu, 0);
EnableItem(edit2Menu, 0);
EnableItem(edit2Menu, MKDIR_MENUITEM);
EnableItem(edit2Menu, ADD_VAR_MENUITEM);
EnableItem(edit2Menu, ADD_SHAREDVAR_MENUITEM);
EnableItem(edit2Menu, ADD_METHOD_MENUITEM);
EnableItem(edit2Menu, HIDE_SHOW_MENUITEM);
EnableItem(edit2Menu, THIS_ONLY_MENUITEM);
EnableItem(edit2Menu, WHOLE_FAMILY_MENUITEM);
EnableItem(edit2Menu, DERIVATIVES_MENUITEM);
if (GUIMode != GUIBrowser) {
/* Remove the previous menus */
ClearMenuBar();
InsertMenu(appleMenu, 0);
InsertMenu(fileMenu, 0);
InsertMenu(edit2Menu, 0);
InsertMenu(viewMenu, 0);
InsertMenu(toolsMenu, 0);
InsertMenu(multitaskMenu, 0);
InsertMenu(windowMenu, 0);
/* UNDO has not been implemented in the browser */
DisableItem(edit2Menu, UNDO_MENUITEM);
DrawMenuBar();
GUIMode = GUIBrowser;
}
else DrawMenuBar();
return;
}
}
/* Disable appropriate menu items */
void doMenuDisable()
{
/* Do general disabling/enabling operations */
doConsoleDisable();
doBrowserDisable();
/* Do menu-specific disabling/enabling */
doDebugMenuDisable();
}
/*
Disable certain menu items if the console window
or a transcript window is selected. This can be known
by checking 'theTask' and the window kind of the frontmost window.
*/
void doConsoleDisable()
{
WindowPtr thisWindow = FrontWindow();
int wKind = getWindowKind(thisWindow);
/* Window has no associated task -> disable certain menu items */
if (!theTask && wKind != BrowserWKind && wKind != CloneBrWKind) {
switch (GUIMode) {
case GUIShell:
/* Disable all the items in context and command menus */
DisableItem(tasksMenu, 0);
DisableItem(debugMenu, SET_BREAK_MENUITEM);
DisableItem(debugMenu, REMOVE_BREAK_MENUITEM);
DisableItem(edit1Menu, BROWSE_MENUITEM);
break;
case GUIBrowser:
/* Disable all the items in other than file and edit menus */
DisableItem(viewMenu, 0);
DisableItem(toolsMenu, 0);
DisableItem(edit2Menu, MKDIR_MENUITEM);
DisableItem(edit2Menu, ADD_VAR_MENUITEM);
DisableItem(edit2Menu, ADD_SHAREDVAR_MENUITEM);
DisableItem(edit2Menu, ADD_METHOD_MENUITEM);
DisableItem(edit2Menu, HIDE_SHOW_MENUITEM);
DisableItem(edit2Menu, THIS_ONLY_MENUITEM);
DisableItem(edit2Menu, WHOLE_FAMILY_MENUITEM);
DisableItem(edit2Menu, DERIVATIVES_MENUITEM);
break;
}
}
}
/*
Enable/disable certain menu items if we are currently in the
browsing mode.
*/
void doBrowserDisable()
{
WindowPtr thisWindow = FrontWindow();
int wKind = getWindowKind(thisWindow);
/* Disable/enable family items from the view menu when browsing */
if (wKind != BrowserWKind && wKind != CloneBrWKind) return;
else {
OBJECT* cwd = getBrowserTarget(thisWindow);
LIST* cwdFamily = getContext(cwd)->cloneFamily;
/* Disable/enable the clone family menu item */
if (cwdFamily && cwdFamily->logicalSize > 0)
EnableItem(viewMenu, SHOW_CLONEF_MENUITEM);
else DisableItem(viewMenu, SHOW_CLONEF_MENUITEM);
/* Disable/enable the parent families menu item */
switch(wKind) {
case BrowserWKind:
cwdFamily = getContext(cwd)->parentFamilies;
break;
case CloneBrWKind:
/* Note: this assumes that clone family has at least one member */
cwd = fetchFromList((LIST*)getBrowserTarget(thisWindow), 1);
cwdFamily = getContext(cwd)->parentFamilies;
}
if (cwdFamily && cwdFamily->logicalSize > 0)
EnableItem(viewMenu, SHOW_PARENTF_MENUITEM);
else DisableItem(viewMenu, SHOW_PARENTF_MENUITEM);
/* Disable/enable the child families menu item */
switch(wKind) {
case BrowserWKind:
cwdFamily = getContext(cwd)->childFamilies;
break;
case CloneBrWKind:
/* Note: this assumes that clone family has at least one member */
/* cwd = fetchFromList((LIST*)getBrowserTarget(thisWindow), 1); done above */
cwdFamily = getContext(cwd)->childFamilies;
break;
}
if (cwdFamily && cwdFamily->logicalSize > 0)
EnableItem(viewMenu, SHOW_CHILDF_MENUITEM);
else DisableItem(viewMenu, SHOW_CHILDF_MENUITEM);
/* Editing functions are disabled when browsing a clone family */
if (wKind == CloneBrWKind) {
DisableItem(edit2Menu, 0);
DisableItem(toolsMenu, 0);
}
else {
/* Browsing a normal object */
EnableItem(edit2Menu, 0);
EnableItem(toolsMenu, 0);
/* If the object responds to copying operations, enable them */
if (respondsTo(cwd, "share"))
EnableItem(toolsMenu, SHARE_MENUITEM);
else DisableItem(toolsMenu, SHARE_MENUITEM);
if (respondsTo(cwd, "clone"))
EnableItem(toolsMenu, CLONE_MENUITEM);
else DisableItem(toolsMenu, CLONE_MENUITEM);
if (respondsTo(cwd, "new"))
EnableItem(toolsMenu, NEW_MENUITEM);
else DisableItem(toolsMenu, NEW_MENUITEM);
/* This has been removed from the menus:
if (respondsTo(cwd, "deepCopy"))
EnableItem(toolsMenu, DEEP_COPY_MENUITEM);
else DisableItem(toolsMenu, DEEP_COPY_MENUITEM);
*/
/* If the second topmost window is not an object browser */
/* disable assignment */
{
ListHandle iconList = getBrowserIcons(thisWindow);
WindowPtr secondWindow = (WindowPtr)((WindowPeek)thisWindow)->nextWindow;
PAIR* tempPair;
if (secondWindow && getWindowKind(secondWindow) == BrowserWKind &&
getBrowserTarget(secondWindow) && countSelectedCells(iconList) == 1) {
Cell cell;
int pairKind;
cell.h = -1; cell.v = 0;
(void)nextSelectedCell(iconList, &cell);
tempPair = cellToPair(thisWindow, cell);
if (!tempPair) goto forw; /* Array slot cannot be assigned to */
pairKind = recognizeObject(tempPair->ofa);
if (pairKind == REF || pairKind == VAR) EnableItem(toolsMenu, ASSIGN_MENUITEM);
else goto forw;
}
else forw: DisableItem(toolsMenu, ASSIGN_MENUITEM);
}
}
}
}
/* Enable/disable items in the debug menu */
void doDebugMenuDisable()
{
/* RESUME in debug menu is enabled only when the chosen task is to be debugged */
if (theTask && theTask == debugTask)
EnableItem(debugMenu, RESUME_MENUITEM);
else DisableItem(debugMenu, RESUME_MENUITEM);
}
/* Set/reset certain markers in the menu bar */
/* This must be executed when the user opens a menu */
void doMenuMarkers()
{
doMultitaskMenuMark();
doDebugMenuMark();
doViewMenuMark();
doEdit2MenuMark();
doWindowMenuMark();
}
/* Change the markers in the multitasking menu */
void doMultitaskMenuMark()
{
if (multitasking)
/* previously: (!inProtRegion && multitasking) || (inProtRegion && mtStore)) */
SetItemMark(multitaskMenu, MON_MOFF_MENUITEM, checkMark);
else SetItemMark(multitaskMenu, MON_MOFF_MENUITEM, noMark);
switch(mtaskMode) {
case PREEMPTIVE:
SetItemMark(multitaskMenu, PREEMPTIVE_MENUITEM, diamondMark);
SetItemMark(multitaskMenu, COOPERATIVE_MENUITEM, noMark);
break;
case COOPERATIVE:
SetItemMark(multitaskMenu, COOPERATIVE_MENUITEM, diamondMark);
SetItemMark(multitaskMenu, PREEMPTIVE_MENUITEM, noMark);
break;
}
}
/* Change the markers in the debugging menu */
void doDebugMenuMark()
{
switch(traceMode) {
case TRACE:
SetItemMark(debugMenu, TRACE_MENUITEM, diamondMark);
SetItemMark(debugMenu, FULLTRACE_MENUITEM, noMark);
SetItemMark(debugMenu, NOTRACE_MENUITEM, noMark);
break;
case FULLTRACE:
SetItemMark(debugMenu, TRACE_MENUITEM, noMark);
SetItemMark(debugMenu, FULLTRACE_MENUITEM, diamondMark);
SetItemMark(debugMenu, NOTRACE_MENUITEM, noMark);
break;
case NOTRACE:
SetItemMark(debugMenu, TRACE_MENUITEM, noMark);
SetItemMark(debugMenu, FULLTRACE_MENUITEM, noMark);
SetItemMark(debugMenu, NOTRACE_MENUITEM, diamondMark);
break;
}
}
/* Change the markers in the view menu */
void doViewMenuMark()
{
WindowPtr thisWindow = FrontWindow();
ListHandle iconList;
if (GUIMode == GUIBrowser && (iconList = getBrowserIcons(thisWindow))) {
int columns = ((*iconList)->dataBounds).right;
int viewMode = getViewMode(iconList);
SetItemMark(viewMenu, ONE_COLUMN_MENUITEM, noMark);
SetItemMark(viewMenu, FOUR_COLUMNS_MENUITEM, noMark);
SetItemMark(viewMenu, VIEW_OPER_MENUITEM, noMark);
SetItemMark(viewMenu, VIEW_DATA_MENUITEM, noMark);
SetItemMark(viewMenu, VIEW_BOTH_MENUITEM, noMark);
if (columns == 1)
SetItemMark(viewMenu, ONE_COLUMN_MENUITEM, diamondMark);
else SetItemMark(viewMenu, FOUR_COLUMNS_MENUITEM, diamondMark);
switch (viewMode) {
case ALL:
SetItemMark(viewMenu, VIEW_BOTH_MENUITEM, diamondMark);
break;
case DATA:
SetItemMark(viewMenu, VIEW_DATA_MENUITEM, diamondMark);
break;
case BEHAVIOR:
SetItemMark(viewMenu, VIEW_OPER_MENUITEM, diamondMark);
break;
}
}
}
/* Change the markers in the edit2 menu */
void doEdit2MenuMark()
{
if (GUIMode != GUIBrowser) return;
SetItemMark(edit2Menu, THIS_ONLY_MENUITEM, noMark);
SetItemMark(edit2Menu, WHOLE_FAMILY_MENUITEM, noMark);
SetItemMark(edit2Menu, DERIVATIVES_MENUITEM, noMark);
switch (whoToModify) {
case THIS_ONLY:
SetItemMark(edit2Menu, THIS_ONLY_MENUITEM, diamondMark);
break;
case WHOLE_FAMILY:
SetItemMark(edit2Menu, WHOLE_FAMILY_MENUITEM, diamondMark);
break;
case DERIVATIVES:
SetItemMark(edit2Menu, DERIVATIVES_MENUITEM, diamondMark);
break;
}
}
/* Change the contents of the window menu on the basis of Mac's window list */
/*
Note that if you add any command key shortcuts to the window menu
then this operation should be called by 'doMenuDisable()' rather than
'doMenuMarkers'.
*/
void doWindowMenuMark()
{
WindowPtr thisWindow = FrontWindow();
short windowKind;
short count;
/* Empty the possible previous contents of the window menu */
count = CountMItems(windowMenu);
while (count) DelMenuItem(windowMenu, count--);
/* Enable/disable window hiding and move behind operations */
if (countVisibleWindows() > 1)
AppendMenu(windowMenu, "\pHide;Move Behind;(-");
else AppendMenu(windowMenu, "\p(Hide;(Move Behind;(-");
/* Enable/disable the 'close browsers' operation */
if (browserCount > 0 && runningCount > 1)
AppendMenu(windowMenu, "\pClose Browsers;(-");
else AppendMenu(windowMenu, "\p(Close Browsers;(-");
/* The menu contains five items before the window names */
count = 5;
/* Show the titles of the windows in the menu */
/* The hidden window will be denoted with a */
/* diamond mark in front of the menu items */
while (thisWindow) {
count++;
GetWTitle(thisWindow, (Str255*)charbuffer);
/* Remove the possible meta characters from the window name */
replaceMenuMetas(charbuffer);
AppendMenu(windowMenu, (Str255*)charbuffer);
if (!((WindowPeek)thisWindow)->visible)
SetItemMark(windowMenu, count, 215); /* 215 = open diamond mark */
thisWindow = (WindowPtr)((WindowPeek)thisWindow)->nextWindow;
}
}
/* Standard error message for 'doMenuItem()' */
void noActiveTask()
{
fprintf(confile, "== The current window has no active task to carry out the operation ==\n");
}
/* Select an item from the menu */
void doMenuItem(menuresult)
long menuresult;
{
short menuId, itemNumber;
menuId = HiWord(menuresult);
itemNumber = LoWord(menuresult);
/* printf("Menu id: %d, item number: %d.\n", menuId, itemNumber); */
switch (menuId) {
case APPLE_MENU:
if (itemNumber == 1) aboutKevo();
else {
Str255 daName;
GrafPtr savePort;
GetItem (appleMenu, itemNumber, daName);
GetPort(&savePort);
OpenDeskAcc(&daName);
SetPort(savePort);
}
break;
case FILE_MENU:
switch (itemNumber) {
case NEW_TASK_MENUITEM: {
TASK** newTask = buildTask();
WindowPtr newWindow;
/* Build a new TextEdit window for the newly created task */
newWindow = buildTEWindow("\pKevo Task");
if (newWindow) {
(*newTask)->window = (int*)newWindow;
ShowWindow(newWindow);
SelectWindow(newWindow);
}
activateTask(newTask);
break;
}
case NEW_SCRIPT_MENUITEM: {
WindowPtr newWindow = buildTEWindow("\pKevo Transcript");
ShowWindow(newWindow);
SelectWindow(newWindow);
break;
}
case SAVE_IMAGE_MENUITEM:
break;
case QUIT_MENUITEM:
pBye();
break;
}
break;
case EDIT1_MENU:
case EDIT2_MENU:
if (SystemEdit(itemNumber-1)) break;
switch (itemNumber) {
case BROWSE_MENUITEM /* Also UNDO */ :
if (theTask) {
OBJECT* target = getTaskCWD(theTask);
openBrowser(target, NIL, BrowserWKind);
}
else openBrowser(oUserRoot, "Root", BrowserWKind);
break;
case CUT_MENUITEM:
doCut();
break;
case COPY_MENUITEM:
doCopy();
break;
case PASTE_MENUITEM:
doPaste();
break;
case CLEAR_MENUITEM:
doRemove();
break;
case SELECT_ALL_MENUITEM:
doSelectAll();
break;
/* The edit operations below this point are used only in the browser mode */
case MKDIR_MENUITEM:
addNewCell(FrontWindow(), REF+8, "untitled");
break;
case ADD_VAR_MENUITEM:
addNewCell(FrontWindow(), VAR, "untitled");
break;
case ADD_SHAREDVAR_MENUITEM:
addNewCell(FrontWindow(), REF, "untitled");
break;
case ADD_METHOD_MENUITEM:
addNewCell(FrontWindow(), METHOD, "untitled");
break;
case HIDE_SHOW_MENUITEM:
doShowHide();
break;
case THIS_ONLY_MENUITEM:
whoToModify = THIS_ONLY;
break;
case WHOLE_FAMILY_MENUITEM:
whoToModify = WHOLE_FAMILY;
break;
case DERIVATIVES_MENUITEM:
whoToModify = DERIVATIVES;
break;
}
break;
case TASKS_MENU:
switch (itemNumber) {
case CANCEL_MENUITEM:
doCancel();
break;
case SUSPEND_MENUITEM:
if (theTask) {
if (yieldingSuspend(theTask))
fprintf(confile, "== Task %d suspended ==\n", theTask);
else fprintf(confile, "== Cannot suspend the only active task in the system ==\n");
}
else fprintf(confile, "== The current window contains no task which could be suspended ==\n");
break;
case ACTIVATE_MENUITEM:
if (theTask) {
activateTask(theTask);
fprintf(confile, "== Task %d activated ==\n", theTask);
/* If singletasking, start executing the just activated task */
if (!multitasking) doSelectTask(FrontWindow(), theTask);
}
else fprintf(confile, "== The current window contains no task which could be activated ==\n");
break;
case LOWER_PR_MENUITEM:
if (theTask) {
pushData((int)theTask);
pLowerPriority();
fprintf(confile, "== Task %d priority now %d ==\n", theTask, (*theTask)->priority);
}
else fprintf(confile, "== The current window contains no task whose priority could be lowered ==\n");
break;
case HIGHER_PR_MENUITEM:
if (theTask) {
pushData((int)theTask);
pRaisePriority();
fprintf(confile, "== Task %d priority now %d ==\n", theTask, (*theTask)->priority);
}
else fprintf(confile, "== The current window contains no task whose priority could be raised ==\n");
break;
}
break;
case MULTITASK_MENU:
switch (itemNumber) {
case PREEMPTIVE_MENUITEM:
cooperativeFlag = -1;
break;
case COOPERATIVE_MENUITEM:
cooperativeFlag = 1;
break;
case MON_MOFF_MENUITEM:
if (multitasking) {
multitasking = FALSE;
doSelectTask(FrontWindow(), determineTask(FrontWindow()));
}
else multitasking = TRUE;
break;
case RESET_MENUITEM:
if (multitasking && mtaskMode == PREEMPTIVE) break;
multitasking = TRUE;
cooperativeFlag = -1;
break;
}
break;
case DEBUG_MENU:
switch (itemNumber) {
case NOTRACE_MENUITEM:
traceFlag = QUITTRACE;
break;
case TRACE_MENUITEM:
traceFlag = TRACE;
break;
case FULLTRACE_MENUITEM:
traceFlag = FULLTRACE;
break;
case SET_BREAK_MENUITEM:
if (theTask) {
char c;
char* ClipBuf = (char*)*TEScrapHandle();
int ClipLen = TEGetScrapLen();
textToKeyBuffer(theTask, "' ");
while (ClipLen-- && (c = *ClipBuf++) > BL) putToKeyBuffer(theTask, c);
textToKeyBuffer(theTask, " debug");
/* Command lines must be separated by two returns or linefeeds */
crsToKeyBuffer(theTask);
}
else noActiveTask();
break;
case REMOVE_BREAK_MENUITEM:
if (theTask) {
char c;
char* ClipBuf = (char*)*TEScrapHandle();
int ClipLen = TEGetScrapLen();
textToKeyBuffer(theTask, "' ");
while (ClipLen-- && (c = *ClipBuf++) > BL) putToKeyBuffer(theTask, c);
textToKeyBuffer(theTask, " unbug");
/* Command lines must be separated by two returns or linefeeds */
crsToKeyBuffer(theTask);
}
else noActiveTask();
break;
case RESUME_MENUITEM:
if (theTask) {
textToKeyBuffer(theTask, "resume");
crsToKeyBuffer(theTask);
}
else noActiveTask();
break;
}
break;
case VIEW_MENU:
switch (itemNumber) {
case VIEW_OPER_MENUITEM: {
ListHandle iconList = getBrowserIcons(FrontWindow());
if (getViewMode(iconList) == BEHAVIOR) break;
setViewMode(iconList, BEHAVIOR);
updateBrowser(FrontWindow());
}
break;
case VIEW_DATA_MENUITEM: {
ListHandle iconList = getBrowserIcons(FrontWindow());
if (getViewMode(iconList) == DATA) break;
setViewMode(iconList, DATA);
updateBrowser(FrontWindow());
}
break;
case VIEW_BOTH_MENUITEM: {
ListHandle iconList = getBrowserIcons(FrontWindow());
if (getViewMode(iconList) == ALL) break;
setViewMode(iconList, ALL);
updateBrowser(FrontWindow());
}
break;
case SHOW_ROOT_MENUITEM:
openBrowser(oUserRoot, "Root", BrowserWKind);
break;
case SHOW_CLONEF_MENUITEM: {
/* Open a browser for the clone family object */
OBJECT* cwd = getBrowserTarget(FrontWindow());
LIST* cf = (LIST*)getContext(cwd)->cloneFamily;
/* Clone family field is zero or clone family size is zero -> do nothing */
if (!cf || cf->logicalSize == 0) {
SysBeep(1);
break;
}
openBrowser((OBJECT*)cf, NIL, CloneBrWKind);
break;
}
case SHOW_PARENTF_MENUITEM: {
browseCloneFamilies(FrontWindow(), "parent");
break;
}
case SHOW_CHILDF_MENUITEM: {
browseCloneFamilies(FrontWindow(), "child");
break;
}
case ONE_COLUMN_MENUITEM:
recolumnBrowser(FrontWindow(), 1);
break;
case FOUR_COLUMNS_MENUITEM: {
recolumnBrowser(FrontWindow(), 4);
break;
}
case UPDATE_MENUITEM:
/* For speed, use 'refreshBrowser' rather than 'updateBrowser' */
refreshBrowser(FrontWindow());
break;
}
break;
case TOOLS_MENU: {
WindowPtr browserWindow = FrontWindow();
OBJECT* cwd = getBrowserTarget(browserWindow);
switch (itemNumber) {
case SHARE_MENUITEM:
if (respondsTo(cwd, "share") && respondsTo(cwd, "browse")) {
numberToKeyBuffer(browserTask, (int)cwd);
textToKeyBuffer(browserTask, ".share.browse");
crsToKeyBuffer(browserTask);
}
break;
case CLONE_MENUITEM:
if (respondsTo(cwd, "clone") && respondsTo(cwd, "browse")) {
numberToKeyBuffer(browserTask, (int)cwd);
textToKeyBuffer(browserTask, ".clone.browse");
crsToKeyBuffer(browserTask);
}
break;
case NEW_MENUITEM:
if (respondsTo(cwd, "new") && respondsTo(cwd, "browse")) {
numberToKeyBuffer(browserTask, (int)cwd);
textToKeyBuffer(browserTask, ".new.browse");
crsToKeyBuffer(browserTask);
}
break;
/* This has been removed from the menus:
case DEEP_COPY_MENUITEM:
if (respondsTo(cwd, "deepCopy") && respondsTo(cwd, "browse")) {
numberToKeyBuffer(browserTask, (int)cwd);
textToKeyBuffer(browserTask, ".deepCopy.browse");
crsToKeyBuffer(browserTask);
}
break;
*/
case ASSIGN_MENUITEM: {
/* The object to be assigned must be the second topmost window */
WindowPtr secondWindow = (WindowPtr)((WindowPeek)browserWindow)->nextWindow;
OBJECT* source;
if (secondWindow && getWindowKind(secondWindow) == BrowserWKind &&
(source = getBrowserTarget(secondWindow)))
assignObject(browserWindow, source);
else {
SysBeep(1);
fprintf(confile, "== Cannot assign (the second topmost window is not an object/browser) ==\n");
}
break;
}
case OPEN_SHELL_MENUITEM:
openShellForThis(cwd);
break;
}
break;
}
case WINDOW_MENU: {
switch (itemNumber) {
case HIDE_WINDOW_MENUITEM:
HideWindow(FrontWindow());
break;
case MOVE_BEHIND_MENUITEM:
SendBehind(FrontWindow(), 0);
break;
case CLOSE_BROWSERS_MENUITEM: {
WindowPtr thisBr = LastBrowser;
WindowPtr tempBr;
OBJECT* target;
if (countVisibleWindows() <= 1) {
fprintf(confile, "== Cannot close the only visible window in the system ==\n");
break;
}
while (thisBr) {
tempBr = getPrevBrowser(thisBr);
target = getBrowserTarget(thisBr);
if (multitasking) {
/*
Set the browser to be deleted by the browser task so as to allow
multitasking to operate without interruption.
In singletasking mode, we must delete the browsers directly
using 'deleteBrowser', since the browser task may not be active.
*/
numberToKeyBuffer(browserTask, (int)target);
textToKeyBuffer(browserTask, " unbrowse");
crsToKeyBuffer(browserTask);
}
else deleteBrowser(thisBr);
thisBr = tempBr;
}
break;
}
default: {
/* Select the correct window, and show it if it is currently invisible */
/* The menu contains five items before the window names */
WindowPtr thisWindow = FrontWindow();
int count = itemNumber-5;
short menuMark;
while (--count) thisWindow = (WindowPtr)((WindowPeek)thisWindow)->nextWindow;
GetItemMark(windowMenu, itemNumber, &menuMark);
if (menuMark) ShowWindow(thisWindow);
SelectWindow(thisWindow);
break;
}
}
}
}
HiliteMenu(FALSE);
}